//
//  SGConsoleLog.swift
//  SGSwiftExtensionDemo
//
//  Created by xyanl on 2025/5/27.
//
// MARK: - SGLogBeautifier.swift
// 完整版日志美化系统 - 支持字典、数组等对象的优雅打印
// 功能特性：
// 1. 自动美化 NSDictionary 和 NSArray 的输出格式
// 2. 支持 URL、Date 等特殊类型的优化显示
// 3. 可配置的格式化选项
// 4. 递归深度保护机制
// 5. 线程安全的方法交换
// 仅在 DEBUG 模式下生效

#if DEBUG

import Foundation

// MARK: - 日志配置系统

/// 日志美化全局配置
public struct LoggerConfig {
    /// 单例共享实例
    public static var shared = LoggerConfig()
    
    // MARK: 格式化选项
    /// 是否启用日志美化（默认开启）
    public var enabled: Bool = true
    /// 最大递归深度（防止循环引用）
    public var maxRecursionDepth: Int = 10
    /// 是否对字典键排序（iOS11+）
    public var sortDictionaryKeys: Bool = true
    /// 是否转义斜杠（iOS13+）
    public var escapeSlashes: Bool = false
    /// 是否显示数据类型前缀
    public var showDataTypePrefix: Bool = false
    /// 日期格式化字符串
    public var dateFormat: String = "yyyy-MM-dd HH:mm:ss.SSS"
    /// 日志最大长度（0表示不限制）
    public var maxLogLength: Int = 0
    /// 缩进空格数
    public var indentSpaces: Int = 2
}

// MARK: - 线程安全的方法交换

private struct SwizzleLock {
    private static let lock = NSLock()  // 线程安全锁
    
    /// 线程安全的同步执行方法
    static func synchronized(_ block: () -> Void) {
        lock.lock()
        defer { lock.unlock() }  // 确保锁一定会被释放
        block()
    }
}

/// 安全的方法交换实现
private func safeSwizzle(classType: AnyClass,
                         original: Selector,
                         swizzled: Selector) {
    SwizzleLock.synchronized {
        // 获取原始方法和交换方法
        guard let originalMethod = class_getInstanceMethod(classType, original),
              let swizzledMethod = class_getInstanceMethod(classType, swizzled) else {
            print("⚠️ 方法交换失败: 方法未找到")
            return
        }
        
        // 防止重复交换
        let key = NSStringFromSelector(original)
        if objc_getAssociatedObject(classType, key) != nil { return }
        objc_setAssociatedObject(classType, key, true, .OBJC_ASSOCIATION_RETAIN)
        
        // 尝试添加方法
        let didAdd = class_addMethod(classType,
                                     original,
                                     method_getImplementation(swizzledMethod),
                                     method_getTypeEncoding(swizzledMethod))
        
        if didAdd {
            // 如果添加成功，替换实现
            class_replaceMethod(classType,
                                swizzled,
                                method_getImplementation(originalMethod),
                                method_getTypeEncoding(originalMethod))
        } else {
            // 否则直接交换实现
            method_exchangeImplementations(originalMethod, swizzledMethod)
        }
    }
}

// MARK: - 递归保护系统

private struct RecursionGuard {
    private static var depth: Int = 0  // 当前递归深度
    
    /// 进入递归保护，返回是否允许继续递归
    static func enter() -> Bool {
        if depth >= LoggerConfig.shared.maxRecursionDepth {
            print("⚠️ 达到最大递归深度(\(LoggerConfig.shared.maxRecursionDepth))")
            return false
        }
        depth += 1
        return true
    }
    
    /// 离开递归保护
    static func leave() {
        depth -= 1
    }
}

// MARK: - 核心美化引擎

extension NSObject {
    /// 将对象转换为美化后的字符串
    /// - Parameter depth: 当前递归深度，用于缩进控制
    fileprivate func beautifiedDescription(depth: Int = 0) -> String {
        // 检查是否启用美化
        guard LoggerConfig.shared.enabled else { return description }
        // 检查递归深度
        guard RecursionGuard.enter() else { return description }
        defer { RecursionGuard.leave() }  // 确保一定会离开递归保护
        
        // 特殊类型处理
        if let date = self as? Date {
            return beautified(date: date)
        }
        
        if let url = self as? URL {
            return beautified(url: url, depth: depth)
        }
        
        if let dict = self as? NSDictionary {
            return beautified(dictionary: dict, depth: depth)
        }
        
        if let array = self as? NSArray {
            return beautified(array: array, depth: depth)
        }
        
        if let string = self as? NSString {
            return beautified(string: string)
        }
        
        if let number = self as? NSNumber {
            return beautified(number: number)
        }
        
        if self is NSNull {
            return beautifiedNull()
        }
        
        // 默认处理
        return defaultBeautifiedDescription()
    }
    
    // MARK: - 各类型美化方法
    
    /// 美化日期对象
    private func beautified(date: Date) -> String {
        let formatter = DateFormatter()
        formatter.dateFormat = LoggerConfig.shared.dateFormat
        return "\"\(formatter.string(from: date))\""
    }
    
    /// 美化URL对象
    private func beautified(url: URL, depth: Int) -> String {
        // 分解URL组件
        let components: [String: Any] = [
            "absoluteString": url.absoluteString,
            "scheme": url.scheme ?? "nil",
            "host": url.host ?? "nil",
            "port": url.port ?? 0,
            "path": url.path,
            "query": url.query ?? "nil",
            "fragment": url.fragment ?? "nil"
        ]
        
        var result = "{\n"
        let indent = String(repeating: " ", count: (depth + 1) * LoggerConfig.shared.indentSpaces)
        
        // 格式化每个组件
        for (key, value) in components {
            let coloredKey = "\"\(key)\""
            let coloredValue = "\"\(value)\""
            result += "\(indent)\(coloredKey): \(coloredValue),\n"
        }
        
        // 移除最后的逗号和换行
        if !components.isEmpty {
            result.removeLast(2)
        }
        
        result += "\n\(String(repeating: " ", count: depth * LoggerConfig.shared.indentSpaces))}"
        return result
    }
    
    /// 美化字典对象
    private func beautified(dictionary: NSDictionary, depth: Int) -> String {
        guard let dict = dictionary as? [String: Any] else { return dictionary.description }
        
        var result = "{\n"
        let indent = String(repeating: " ", count: (depth + 1) * LoggerConfig.shared.indentSpaces)
        
        // 根据配置决定是否排序键
        let keys = LoggerConfig.shared.sortDictionaryKeys ?
        dict.keys.sorted() :
        Array(dict.keys)
        
        // 格式化每个键值对
        for key in keys {
            guard let value = dict[key] else { continue }
            let coloredValue = (value as? NSObject)?.beautifiedDescription(depth: depth + 1) ?? "\(value)"
            result += "\(indent)\"\(key)\": \(coloredValue),\n"
        }
        
        // 移除最后的逗号和换行
        if !dict.isEmpty {
            result.removeLast(2)
        }
        
        result += "\n\(String(repeating: " ", count: depth * LoggerConfig.shared.indentSpaces))}"
        
        // 添加类型前缀
        if LoggerConfig.shared.showDataTypePrefix {
            result = "[Dictionary] " + result
        }
        
        return result
    }
    
    /// 美化数组对象
    private func beautified(array: NSArray, depth: Int) -> String {
        guard let arr = array as? [Any] else { return array.description }
        
        var result = "[\n"
        let indent = String(repeating: " ", count: (depth + 1) * LoggerConfig.shared.indentSpaces)
        
        // 格式化每个元素
        for element in arr {
            let coloredElement = (element as? NSObject)?.beautifiedDescription(depth: depth + 1) ?? "\(element)"
            result += "\(indent)\(coloredElement),\n"
        }
        
        // 移除最后的逗号和换行
        if !arr.isEmpty {
            result.removeLast(2)
        }
        
        result += "\n\(String(repeating: " ", count: depth * LoggerConfig.shared.indentSpaces))]"
        
        // 添加类型前缀
        if LoggerConfig.shared.showDataTypePrefix {
            let prefix = "[Array(\(arr.count))] "
            result = prefix + result
        }
        
        return result
    }
    
    /// 美化字符串
    private func beautified(string: NSString) -> String {
        var str = string as String
        // 处理长度限制
        if LoggerConfig.shared.maxLogLength > 0 && str.count > LoggerConfig.shared.maxLogLength {
            let end = str.index(str.startIndex, offsetBy: LoggerConfig.shared.maxLogLength)
            str = String(str[..<end]) + "...[截断]"
        }
        return "\"\(str)\""
    }
    
    /// 美化数字
    private func beautified(number: NSNumber) -> String {
        // 检查是否是布尔值
        let objCType = String(cString: number.objCType)
        if objCType == "c" || objCType == "B" {
            let boolValue = number.boolValue
            return "\(boolValue ? "true" : "false")"
        }
        
        return "\(number)"
    }
    
    /// 美化空值
    private func beautifiedNull() -> String {
        return "null"
    }
    
    /// 默认美化处理
    private func defaultBeautifiedDescription() -> String {
        var desc = description
        
        // 处理长度限制
        if LoggerConfig.shared.maxLogLength > 0 && desc.count > LoggerConfig.shared.maxLogLength {
            let end = desc.index(desc.startIndex, offsetBy: LoggerConfig.shared.maxLogLength)
            desc = String(desc[..<end]) + "...[截断]"
        }
        
        return desc
    }
}

// MARK: - NSDictionary 扩展 (方法交换)

extension NSDictionary {
    // 交换后的方法实现
    @objc private func printlog_description(withLocale locale: Any?) -> String {
        return beautifiedDescription()
    }
    
    @objc private func printlog_description(withLocale locale: Any?, indent level: Int) -> String {
        return beautifiedDescription(depth: level)
    }
    
    @objc private func printlog_debugDescription() -> String {
        return beautifiedDescription()
    }
    
    /// 设置方法交换
    fileprivate static func setupSwizzling() {
        // 交换三个描述方法
        safeSwizzle(classType: self,
                    original: #selector(description(withLocale:)),
                    swizzled: #selector(printlog_description(withLocale:)))
        
        safeSwizzle(classType: self,
                    original: #selector(description(withLocale:indent:)),
                    swizzled: #selector(printlog_description(withLocale:indent:)))
        
        safeSwizzle(classType: self,
                    original: #selector(debugDescription),
                    swizzled: #selector(printlog_debugDescription))
    }
}

// MARK: - NSArray 扩展 (方法交换)

extension NSArray {
    // 交换后的方法实现
    @objc private func printlog_description(withLocale locale: Any?) -> String {
        return beautifiedDescription()
    }
    
    @objc private func printlog_description(withLocale locale: Any?, indent level: Int) -> String {
        return beautifiedDescription(depth: level)
    }
    
    @objc private func printlog_debugDescription() -> String {
        return beautifiedDescription()
    }
    
    /// 设置方法交换
    fileprivate static func setupSwizzling() {
        // 交换三个描述方法
        safeSwizzle(classType: self,
                    original: #selector(description(withLocale:)),
                    swizzled: #selector(printlog_description(withLocale:)))
        
        safeSwizzle(classType: self,
                    original: #selector(description(withLocale:indent:)),
                    swizzled: #selector(printlog_description(withLocale:indent:)))
        
        safeSwizzle(classType: self,
                    original: #selector(debugDescription),
                    swizzled: #selector(printlog_debugDescription))
    }
}

// MARK: - 公开API

public enum SGLogBeautifier {
    /// 启用日志美化系统
    /// - Parameter configuration: 配置闭包，可选
    public static func enable(configuration: ((inout LoggerConfig) -> Void)? = nil) {
        // 应用配置
        if let config = configuration {
            config(&LoggerConfig.shared)
        }
        
        // 设置方法交换
        NSDictionary.setupSwizzling()
        NSArray.setupSwizzling()
        
        print("🔷 SGLogBeautifier 已启用")
        print("当前配置: \(LoggerConfig.shared)")
    }
    
    /// 打印美化后的对象
    /// - Parameter object: 要打印的对象
    public static func print(_ object: Any) {
        if let obj = object as? NSObject {
            Swift.print(obj.beautifiedDescription())
        } else {
            Swift.print(object)
        }
    }
}

// MARK: - LoggerConfig 的 CustomStringConvertible 实现

extension LoggerConfig: CustomStringConvertible {
    public var description: String {
        let mirror = Mirror(reflecting: self)
        var result = "LoggerConfig:\n"
        
        // 反射所有属性
        for child in mirror.children {
            if let label = child.label {
                result += "  - \(label): \(child.value)\n"
            }
        }
        
        return result
    }
}

#endif

/**
 # 使用说明
 1. 在 AppDelegate 的 didFinishLaunchingWithOptions 中初始化，里面有做 `#if DEBUG` 判断,
 ```
 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
     // Override point for customization after application launch.
         
     // 初始化,配置一些属性
     SGLogBeautifier.enable { config in
         config.maxLogLength = 0
         config.dateFormat = "yyyy-MM-dd HH:mm:ss.SSS"
     }
         
     return true
 }
 ```

 2. 使用
 需要将`Dictionary`转成`NSDictionary`,将`Array`转成`NSArray`, swift 的对象要转成 OC 的
 ```
 let sampleDict: [String: Any] = [
     "name": "赵云",
     "age": 30,
     "date": Date(),
     "website": URL(string: "https://example.com/user/12345")!,
     "address": [
         "street": "123 Main St",
         "city": "New York"
     ],
     "hobbies": ["Reading", "Swimming", "Coding"],
     "nullValue": NSNull(),
     "trueValue": true,
     "emptyArray": [],
     "emptyDict": [:],
 ]


 print(sampleDict) // 没有美化格式
 print(sampleDict as NSDictionary) // 有做格式美化
 SGLogBeautifier.print(sampleDict) // 有做格式美化

 输出示例​:

 // 没有美化格式的
 ["website": https://example.com/user/12345, "age": 30, "hobbies": ["Reading", "Swimming", "Coding"], "trueValue": true, "date": 2025-05-27 09:18:23 +0000, "address": ["city": "New York", "street": "123 Main St"], "nullValue": <null>, "emptyArray": [], "emptyDict": [:], "name": "赵云"]

 // 美化格式
 {
   "address": {
     "city": "New York",
     "street": "123 Main St"
   },
   "age": 30,
   "date": "2025-05-27 17:18:23.273",
   "emptyArray": [

   ],
   "emptyDict": {

   },
   "hobbies": [
     "Reading",
     "Swimming",
     "Coding"
   ],
   "name": "赵云",
   "nullValue": null,
   "trueValue": true,
   "website": {
     "port": "0",
     "absoluteString": "https://example.com/user/12345",
     "scheme": "https",
     "host": "example.com",
     "query": "nil",
     "path": "/user/12345",
     "fragment": "nil"
   }
 }

 ```
 */

